package api

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/ethereum/go-ethereum"
	"github.com/ethereum/go-ethereum/accounts/abi"
	"github.com/ethereum/go-ethereum/common"
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/gin-gonic/gin"
	"go-chain-api/contract"
	"go-chain-api/contract/evmAbi"
	"go-chain-api/global"
	models "go-chain-api/internal/model"
	"go-chain-api/tools"
	"go-chain-api/utils"
	"go-chain-api/utils/mail"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"golang.org/x/exp/rand"
	"log"
	"math"
	"math/big"
	"net/http"
	"regexp"
	"strconv"
	"strings"
	"time"
)

type UdunAPI struct {
}

type UserToken struct {
	UserID  uint
	TokenID uint
	Token   models.TokenInfo
}

func (u UdunAPI) Withdraw(c *gin.Context) {
	config := c.MustGet("chainConfig").(models.ScanConfig)
	callBack := c.MustGet("callBack").(string)
	userId := c.MustGet("user_id").(string)
	tokenInfo := c.MustGet("tokenInfo").(models.TokenInfo)
	address := c.MustGet("address").(string)
	amount := c.MustGet("amount").(string)
	memo := c.MustGet("memo").(string)
	businessId := c.MustGet("businessId").(string)
	language := c.MustGet("language").(string)

	businessInt, _ := strconv.Atoi(businessId)

	//判断相同提现
	flag := models.RepeatWithdraw(businessId, userId, tokenInfo.Address)
	if !flag {
		response := utils.GetResponse(errors.New("重复提现!"), utils.ParseDataError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	// 正则表达式：包含数字、小写字母和大写字母 42和34
	if len(address) == 42 || len(address) == 34 {
		pattern := `^[0-9a-zA-Z]+$`
		match, _ := regexp.MatchString(pattern, address)
		if !match {
			response := utils.GetResponse(nil, utils.ParseDataError, fmt.Sprintf("%q", address), language)
			c.JSON(http.StatusBadRequest, response)
			return
		}
	} else {
		response := utils.GetResponse(nil, utils.ParseDataError, fmt.Sprintf("%q", address), language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	var userInfo models.User
	userClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user")
	fromHex, _ := primitive.ObjectIDFromHex(userId)
	err := userClient.FindOne(context.TODO(), bson.M{"_id": fromHex}).Decode(&userInfo)
	if err != nil {
		log.Printf("获取用户信息失败 %s", err.Error())
		return
	}

	var userPrivateKey models.UserPrivateKey
	err = global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key").FindOne(context.TODO(), bson.M{"userId": userId, "mainCoinType": config.UdunId}).Decode(&userPrivateKey)
	if err != nil {
		response := utils.GetResponse(err, utils.GetUserPrivateKeyError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	if tokenInfo.ChainID != config.ChainID {
		response := utils.GetResponse(nil, utils.ChainIdNotMatch, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	addressData := &models.Withdraw{
		ChainId:       uint(config.ChainID),
		Memo:          memo,
		Value:         amount,
		From:          userPrivateKey.WithdrawAddress,
		To:            address,
		BusinessId:    uint(businessInt),
		TokenSymbol:   tokenInfo.Symbol,
		CallBack:      callBack,
		UserId:        userId,
		Timestamp:     uint(time.Now().Unix()),
		Status:        0,
		TokenId:       tokenInfo.Id,
		ChainName:     config.ChainName,
		TokenDecimals: tokenInfo.Decimals,
		MainCoinType:  config.UdunId,
		TokenAddress:  tokenInfo.Address,
	}

	withdrawClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("withdraw")
	InsertData, err := withdrawClient.InsertOne(context.TODO(), addressData)
	if err != nil {
		response := utils.GetResponse(err, utils.InsertError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	verifyVal := models.GetStatus(userId)

	//用户自定义 两种方式 0.一种直接提币 1.另一种是后台审核提币
	if verifyVal == 0 {
		//构建body
		var body models.CallBackBody
		body.Address = addressData.To
		body.Amount = addressData.Value
		body.Fee = 0
		//查询币种精度
		body.Decimals = int(addressData.TokenDecimals)
		body.CoinType = addressData.TokenAddress
		body.MainCoinType = strconv.FormatInt(addressData.MainCoinType, 10)
		body.BusinessId = strconv.Itoa(int(addressData.BusinessId))
		body.TradeId = InsertData.InsertedID.(primitive.ObjectID).Hex()
		body.Memo = addressData.Memo
		body.TradeType = 2

		objId := InsertData.InsertedID.(primitive.ObjectID)
		_, err = withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": objId}, bson.M{"$set": bson.M{"status": 1}})
		if err != nil {
			response := utils.GetResponse(err, utils.UpdateError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		userId = addressData.UserId
		tokenAddress := addressData.TokenAddress
		address = addressData.To
		mainCoinType := addressData.MainCoinType
		amount = addressData.Value
		callBack = addressData.CallBack
		// 发送提币

		body.Status = 3
		switch addressData.ChainName {
		case "TRX":
			var UserPrivatekeys models.UserPrivateKey
			keyClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")
			err = keyClient.FindOne(context.Background(), bson.M{"userId": userId, "mainCoinType": mainCoinType}).Decode(&UserPrivatekeys)
			if err != nil {
				response := utils.GetResponse(err, utils.GetUserPrivateKeyError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			num, _ := strconv.ParseFloat(amount, 64)
			BigintAmount, isOk := tools.EtherStrToWeiBigInt(amount, tokenInfo.Decimals)
			if !isOk {
				response := utils.GetResponse(nil, utils.EthToWeiError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			str := strconv.FormatInt(mainCoinType, 10)
			var typeVal string
			var tokenFlag string
			if tokenAddress != str {
				typeVal = tokenAddress
				tokenFlag = tokenAddress
			} else {
				tokenFlag = "_"
			}
			feeBalance, err := models.GetTrxAmount(UserPrivatekeys.WithdrawAddress, tokenFlag)
			if err != nil {
				response := utils.GetResponse(err, utils.GetCountError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			feeNum, _ := strconv.ParseFloat(feeBalance, 64)
			if feeNum < num {
				withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": objId}, bson.M{"$set": bson.M{"status": 4}})
				response := utils.GetResponse(errors.New("余额不足"), utils.ServerError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			txId, err := contract.GetTrxTransactionSign(address, BigintAmount.String(), typeVal, userPrivateKey.WithdrawBusinessId, "grpc.trongrid.io:50051")

			//txId, err := a.TransferTRC20(token, address, amountInt64)
			if err != nil {
				_, err := withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": objId}, bson.M{"$set": bson.M{"status": 4, "txHash": txId}})
				response := utils.GetResponse(err, utils.TransferError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			go doTrxWithdraw(txId, int(num), &body, userInfo.ApiKey, callBack, objId)

		default:

			var userPrivateKey models.UserPrivateKey
			err := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key").FindOne(context.TODO(), bson.M{"userId": userId, "mainCoinType": mainCoinType}).Decode(&userPrivateKey)
			if err != nil {
				response := utils.GetResponse(err, utils.GetUserPrivateKeyError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			BigintAmount := tools.StrEtherBigInt(amount, addressData.TokenDecimals)
			if BigintAmount.String() == "0" {
				response := utils.GetResponse(nil, utils.EthToWeiError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			var scanConfig models.ScanConfig
			configClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("scan_config")
			err = configClient.FindOne(context.TODO(), bson.D{{"udunId", mainCoinType}, {"type", "DAPP"}}).Decode(&scanConfig)
			if err != nil {
				response := utils.GetResponse(err, utils.MainCoinTypeInvalid, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			clients, err := ethclient.Dial(scanConfig.RpcUrl)
			if err != nil {
				response := utils.GetResponse(err, utils.ConnectRpcUrlError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			str := strconv.FormatInt(mainCoinType, 10)
			if tokenAddress != str {
				go doWithdraw(clients, address, tokenAddress, BigintAmount, &body, userInfo.ApiKey, callBack, objId, userPrivateKey.WithdrawBusinessId, scanConfig.RpcUrl)
			} else {
				go doWithdrawMain(clients, address, str, BigintAmount, &body, userInfo.ApiKey, callBack, objId, userPrivateKey.WithdrawBusinessId, scanConfig.RpcUrl)
			}

		}
	}

	str := "尊敬的BlockWatch会员：\n\n您好！" + address + "发起了提现申请，需要提取" + tokenInfo.ChainName + "链下的" + amount + "个" + tokenInfo.Symbol + "币\r\n"

	emailParams := mail.Options{
		MailHost: global.EmailConfig.Host,
		MailPort: global.EmailConfig.Port,
		MailUser: global.EmailConfig.User,
		MailPass: global.EmailConfig.Password,
		MailTo:   userInfo.Email,
		Subject:  "提币操作提醒",
		Body:     str,
	}
	mail.Send(&emailParams)
	// 发送普通单发邮件
	//mail.SendSingleEmail(0, userInfo.Email, global.EmailConfig.FromEmail, true, global.EmailConfig.FromEmail, "天晟科技", str, "提币操作提醒", "")

	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)
}

func (u UdunAPI) ChangeWithdrawStatus(c *gin.Context) {

	language := c.MustGet("language").(string)
	var data models.WithdrawRequestData
	err := c.ShouldBindJSON(&data)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	objId, _ := primitive.ObjectIDFromHex(data.Id)

	var withdrawInfo models.Withdraw
	withdrawClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("withdraw")
	err = withdrawClient.FindOne(context.TODO(), bson.M{"_id": objId}).Decode(&withdrawInfo)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var userInfo models.User
	userClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user")
	fromHex, _ := primitive.ObjectIDFromHex(withdrawInfo.UserId)
	err = userClient.FindOne(context.TODO(), bson.M{"_id": fromHex}).Decode(&userInfo)

	if withdrawInfo.Status != 0 && withdrawInfo.Status != 4 {
		response := utils.GetResponse(err, utils.RepeatedWithdraw, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	//构建body
	var body models.CallBackBody
	body.Address = withdrawInfo.To
	body.Amount = withdrawInfo.Value
	body.Fee = 0
	//查询币种精度
	body.Decimals = int(withdrawInfo.TokenDecimals)
	body.CoinType = withdrawInfo.TokenAddress
	body.MainCoinType = strconv.FormatInt(withdrawInfo.MainCoinType, 10)
	body.BusinessId = strconv.Itoa(int(withdrawInfo.BusinessId))
	body.TradeId = data.Id
	body.Memo = withdrawInfo.Memo
	body.TradeType = 2

	if data.Status == 1 {
		_, err = withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": objId}, bson.M{"$set": bson.M{"status": 1}})
		if err != nil {
			response := utils.GetResponse(err, utils.UpdateError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		userId := withdrawInfo.UserId
		tokenAddress := withdrawInfo.TokenAddress
		address := withdrawInfo.To
		mainCoinType := withdrawInfo.MainCoinType
		amount := withdrawInfo.Value
		callBack := withdrawInfo.CallBack
		// 发送提币

		var UserPrivatekeys models.UserPrivateKey
		keyClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")
		err = keyClient.FindOne(context.Background(), bson.M{"userId": userId, "mainCoinType": mainCoinType}).Decode(&UserPrivatekeys)
		if err != nil {
			response := utils.GetResponse(err, utils.GetUserPrivateKeyError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}

		body.Status = 3
		switch withdrawInfo.ChainName {
		case "TRX":
			num, _ := strconv.ParseFloat(amount, 64)
			if err != nil {
				response := utils.GetResponse(err, utils.ParseDataError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			//amountInt64 := int64(num * 1000000)

			BigintAmount, isOk := tools.EtherStrToWeiBigInt(amount, withdrawInfo.TokenDecimals)
			if !isOk {
				response := utils.GetResponse(nil, utils.EthToWeiError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			str := strconv.FormatInt(mainCoinType, 10)
			var typeVal string
			var tokenFlag string
			if tokenAddress != str {
				typeVal = tokenAddress
				tokenFlag = tokenAddress
			} else {
				tokenFlag = "_"
			}

			feeBalance, err := models.GetTrxAmount(UserPrivatekeys.WithdrawAddress, tokenFlag)
			if err != nil {
				response := utils.GetResponse(err, utils.GetCountError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			feeNum, _ := strconv.ParseFloat(feeBalance, 64)
			if feeNum < num {
				withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": objId}, bson.M{"$set": bson.M{"status": 4}})
				response := utils.GetResponse(errors.New("余额不足"), utils.ServerError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			//txId, err := a.TransferTRC20(token, address, amountInt64)
			txId, err := contract.GetTrxTransactionSign(address, BigintAmount.String(), typeVal, UserPrivatekeys.WithdrawBusinessId, "grpc.trongrid.io:50051")

			if err != nil {
				_, err := withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": objId}, bson.M{"$set": bson.M{"status": 4, "txHash": txId}})
				response := utils.GetResponse(err, utils.TransferError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			go doTrxWithdraw(txId, int(num), &body, userInfo.ApiKey, callBack, objId)
		default:
			BigintAmount, isOk := tools.EtherStrToWeiBigInt(amount, withdrawInfo.TokenDecimals)
			if !isOk {
				response := utils.GetResponse(nil, utils.EthToWeiError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			var scanConfig models.ScanConfig
			configClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("scan_config")
			err = configClient.FindOne(context.TODO(), bson.D{{"udunId", mainCoinType}, {"type", "DAPP"}}).Decode(&scanConfig)
			if err != nil {
				response := utils.GetResponse(err, utils.MainCoinTypeInvalid, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			clients, err := ethclient.Dial(scanConfig.RpcUrl)
			if err != nil {
				response := utils.GetResponse(err, utils.ConnectRpcUrlError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			str := strconv.FormatInt(mainCoinType, 10)
			if tokenAddress != str {
				go doWithdraw(clients, address, tokenAddress, BigintAmount, &body, userInfo.ApiKey, callBack, objId, UserPrivatekeys.WithdrawBusinessId, scanConfig.RpcUrl)

			} else {
				go doWithdrawMain(clients, address, str, BigintAmount, &body, userInfo.ApiKey, callBack, objId, UserPrivatekeys.WithdrawBusinessId, scanConfig.RpcUrl)
			}

		}

	} else {
		_, err := withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": objId}, bson.M{"$set": bson.M{"status": 2, "memo": data.Memo}})
		if err != nil {
			response := utils.GetResponse(nil, utils.UpdateError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		body.Status = 2
		go func() {
			utils.SendCallBack(&body, userInfo.ApiKey, strconv.Itoa(10000000), strconv.FormatInt(time.Now().Unix(), 10), withdrawInfo.CallBack)
		}()
	}

	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)

}

func (api UdunAPI) GetClient(c *gin.Context) *ethclient.Client {
	clientHandle := c.MustGet("client")
	return clientHandle.(*ethclient.Client)
}

func (u UdunAPI) GetUserTokens(c *gin.Context) {
	language := c.MustGet("language").(string)
	userInfo := c.MustGet("userInfo").(models.User)
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	findOptions := options.Find()
	findOptions.SetSkip(int64(pageIndex))
	findOptions.SetLimit(int64(pageSize))

	filter := bson.M{"userId": userInfo.Id}
	address := c.Query("address")
	symbol := c.Query("symbol")
	if address != "" {
		filter["address"] = address
	}
	if symbol != "" {
		filter["symbol"] = symbol
	}

	var userToken []*models.UserToken
	userTokenClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_token")
	data, err := userTokenClient.Find(context.TODO(), filter, findOptions)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	err = data.All(context.Background(), &userToken)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	documents, err := userTokenClient.CountDocuments(context.TODO(), filter)
	if err != nil {
		response := utils.GetResponse(err, utils.GetCountError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	result := global.Page{
		Total: documents,
		List:  userToken,
	}
	response := utils.GetResponse(nil, utils.Success, result, language)
	c.JSON(http.StatusOK, response)
}

func (u UdunAPI) GenerateAddress(c *gin.Context) {
	config := c.MustGet("chainConfig").(models.ScanConfig)
	language := c.MustGet("language").(string)
	var watchAddressConfig models.WatchAddressConfig
	//var privateKeyHex string
	//var address string
	//switch config.ChainName {
	//case "TRX":
	//	privateKey, _ := crypto.GenerateKey()
	//	privateKeyBytes := crypto.FromECDSA(privateKey)
	//	publicKey := privateKey.Public()
	//	publicKeyECDSA, _ := publicKey.(*ecdsa.PublicKey)
	//	addrStr := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
	//	addrStr = "41" + addrStr[2:]
	//	addb, _ := hex.DecodeString(addrStr)
	//	firstHash := sha256.Sum256(addb)
	//	secondHash := sha256.Sum256(firstHash[:])
	//	secret := secondHash[:4]
	//	addb = append(addb, secret...)
	//	address = base58.Encode(addb)
	//	privateKeyHex = hexutil.Encode(privateKeyBytes)[2:]
	//default:
	//	// 生成私钥
	//	privateKey, err := crypto.GenerateKey()
	//	if err != nil {
	//		response := utils.GetResponse(err, utils.GeneratePrivateError, nil, language)
	//		c.JSON(http.StatusBadRequest, response)
	//		return
	//	}
	//	// 将私钥转换为字节切片
	//	privateKeyBytes := crypto.FromECDSA(privateKey)
	//	// 将字节切片转换为十六进制字符串
	//	privateKeyHex = hex.EncodeToString(privateKeyBytes)
	//	// 生成公钥
	//	publicKey := privateKey.Public().(*ecdsa.PublicKey)
	//	// 生成地址
	//	address = crypto.PubkeyToAddress(*publicKey).Hex()
	//}

	var flag string
	if config.ChainName == "TRX" {
		flag = "TRX"
	} else {
		flag = "EVM"
	}

	url := "http://192.168.0.188:8888/api/generateAddress?flag=" + flag
	body, err := tools.SendGet(url)
	if err != nil {
		response := utils.GetResponse(errors.New("send get error"+err.Error()), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var data models.AddressData
	err = json.Unmarshal(body, &data)
	if err != nil {
		response := utils.GetResponse(errors.New("json parse error"+err.Error()), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	if data.Code != 200 {
		response := utils.GetResponse(errors.New("code is not 200"+data.Msg), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	callBack := c.MustGet("callBack").(string)
	userId := c.MustGet("user_id").(string)

	//这里是存入u盾的address表 所以userId用系统用户的id取创建地址
	watchAddressConfig.UserId = userId
	watchAddressConfig.ChainId = uint(config.ChainID)
	watchAddressConfig.Address = data.Data.Address
	watchAddressConfig.BusinessId = data.Data.Id
	watchAddressConfig.ChainName = config.ChainName
	watchAddressConfig.Type = "udun"
	watchAddressConfig.CallBackUrl = callBack
	watchAddressConfig.Timestamp = uint64(time.Now().Unix())
	err = watchAddressConfig.Insert()
	if err != nil {
		response := utils.GetResponse(err, utils.InsertError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	response := utils.GetResponse(nil, utils.Success, data.Data.Address, language)
	c.JSON(http.StatusOK, response)

}

func (u UdunAPI) DelAddress(c *gin.Context) {

	address := c.MustGet("address").(string)
	userId := c.MustGet("user_id").(string)

	var watchAddressConfig models.WatchAddressConfig
	watchAddressConfig.Address = address
	watchAddressConfig.UserId = userId
	err := watchAddressConfig.DeleteByAddress()
	if err != nil {
		response := global.Response{
			Code: http.StatusInternalServerError,
			Data: nil,
			Msg:  err.Error(),
		}
		c.JSON(http.StatusOK, response)
		return
	}

	response := global.Response{
		Code: http.StatusOK,
		Data: nil,
		Msg:  "success",
	}

	c.JSON(http.StatusOK, response)
}

func (u UdunAPI) UpdateCallBackUrl(c *gin.Context) {
	language := c.MustGet("language").(string)
	var watchAddressConfig models.WatchAddressConfig
	userInfo := c.MustGet("userInfo").(models.User)
	err := c.ShouldBindJSON(&watchAddressConfig)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	var callBackUrl = watchAddressConfig.CallBackUrl

	addressConfigClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	filter := bson.D{{"userId", userInfo.Id},
		{"address", watchAddressConfig.Address},
		{"type", "udun"}}

	err = addressConfigClient.FindOne(context.TODO(), filter).Decode(&watchAddressConfig)
	if errors.Is(err, mongo.ErrNoDocuments) {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	update := bson.D{{"$set", bson.D{{"callBackUrl", callBackUrl}}}}
	_, err = addressConfigClient.UpdateOne(context.TODO(), filter, update)
	if err != nil {
		response := utils.GetResponse(err, utils.UpdateError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	//generateClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("generate_address_config")
	//_, err = generateClient.UpdateOne(context.TODO(), filter, update)
	//if err != nil {
	//	response := global.Response{
	//		Code: http.StatusOK,
	//		Data: nil,
	//		Msg:  "failed updated generate_address_config table " + err.Error(),
	//	}
	//	c.JSON(http.StatusOK, response)
	//	return
	//}

	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)
}

func (u UdunAPI) AddToken(c *gin.Context) {

	language := c.MustGet("language").(string)
	var tokenIds models.TokenIdStr
	err := c.ShouldBindJSON(&tokenIds)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	userInfo := c.MustGet("userInfo").(models.User)

	//userPacketClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")
	//documents, err := userPacketClient.CountDocuments(context.TODO(), bson.M{"userId": userInfo.Id})
	//if err != nil {
	//	response := utils.GetResponse(err, utils.GetCountError, nil, language)
	//	c.JSON(http.StatusOK, response)
	//	return
	//}
	//if documents == 0 {
	//	response.Code = http.StatusInternalServerError
	//	response.Msg = "Asset management is not configured"
	//	c.JSON(http.StatusOK, response)
	//	return
	//}

	//在数据库中创建用户与代币的关联关系
	if err := models.CreateUserToken(userInfo.Id, tokenIds.TokenIds); err != nil {
		response := utils.GetResponse(err, utils.InsertError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)
}

func (u UdunAPI) GetUserAddress(c *gin.Context) {

	language := c.MustGet("language").(string)
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	userInfo := c.MustGet("userInfo").(models.User)
	address := c.Query("address")
	chainId := c.Query("chainId")
	userAddress, total, err := ReadUserAddress(userInfo.Id, pageIndex, pageSize, address, chainId)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	data := global.Page{
		Total: total,
		List:  userAddress,
	}

	response := utils.GetResponse(nil, utils.Success, data, language)
	c.JSON(http.StatusOK, response)
}

func (u UdunAPI) GetOrderList(c *gin.Context) {

	language := c.MustGet("language").(string)
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	//订单编号
	orderId := c.Query("orderId")
	//订单状态
	orderStatus := c.Query("orderStatus")

	userInfo := c.MustGet("userInfo").(models.User)
	// 根据用户id 获取订单列表
	var order []*models.Order

	order, total, err := ReadOrderByID(userInfo.Id, pageIndex, pageSize, orderId, orderStatus)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	for i2, v := range order {
		order[i2].OrderNo = utils.MD5(v.Id)
	}
	data := global.Page{
		Total: total,
		List:  order,
	}
	response := utils.GetResponse(nil, utils.Success, data, language)
	c.JSON(http.StatusOK, response)
}

func doWithdraw(clients *ethclient.Client, address string, tokenAddress string, value *big.Int, body *models.CallBackBody, apikey string, callback string, withdrawId primitive.ObjectID, businessId string, rpcUrl string) {
	withdrawClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("withdraw")
	rand.Seed(uint64(time.Now().UnixNano())) // 初始化随机数种子
	randomInt := rand.Intn(10000000)         // 生成一个0到99的随机整数
	txgj, err := contract.GetTransactionSign(clients, businessId, address, rpcUrl, value.String(), tokenAddress)
	if err != nil {
		_, err = withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": withdrawId}, bson.M{"$set": bson.M{"status": 4}})
		log.Printf("归集失败: %s", err)
		body.Status = 4
		if txgj != nil {
			body.TxId = txgj.Hash().Hex()
		}

		go utils.SendCallBack(body, apikey, strconv.Itoa(randomInt), strconv.FormatInt(time.Now().Unix(), 10), callback)
		return
	}
	//withdrawModel.Status = 3
	//withdrawModel.TxHash = txgj.Hash().Hex()

	_, err = withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": withdrawId}, bson.M{"$set": bson.M{"status": 3, "txHash": txgj.Hash().Hex()}})
	if err != nil {
		log.Printf("存提币哈希失败: %s", err)
		return
	}
	//发送回调
	body.Fee = int(txgj.GasPrice().Int64())
	body.TxId = txgj.Hash().Hex()

	//发送post
	go utils.SendCallBack(body, apikey, strconv.Itoa(randomInt), strconv.FormatInt(time.Now().Unix(), 10), callback)

}

func doWithdrawMain(clients *ethclient.Client, address string, tokenAddress string, value *big.Int, body *models.CallBackBody, apikey string, callback string, withdrawId primitive.ObjectID, businessId string, rpcUrl string) {
	withdrawClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("withdraw")
	//txgj, err := contract.SendTransactionMain(clients, privateKey, value, address)
	txgj, err := contract.GetTransactionSign(clients, businessId, address, rpcUrl, value.String(), "")

	if err != nil {
		_, err = withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": withdrawId}, bson.M{"$set": bson.M{"status": 4}})
		log.Printf("EVM主币转账失败: %s", err)
		return
	}
	//withdrawModel.Status = 3
	//withdrawModel.TxHash = txgj.Hash().Hex()

	_, err = withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": withdrawId}, bson.M{"$set": bson.M{"status": 3, "txHash": txgj.Hash().Hex()}})
	if err != nil {
		log.Printf("存提币哈希失败: %s", err)
		return
	}
	//发送回调
	body.Fee = int(txgj.GasPrice().Int64())
	body.TxId = txgj.Hash().Hex()
	rand.Seed(uint64(time.Now().UnixNano())) // 初始化随机数种子
	randomInt := rand.Intn(10000000)         // 生成一个0到99的随机整数
	//发送post
	go utils.SendCallBack(body, apikey, strconv.Itoa(randomInt), strconv.FormatInt(time.Now().Unix(), 10), callback)

}

func ReadByName(userName string) error {
	user := new(models.UdunUser)
	if err := global.MysqlDbEngine.Table("tian_users").Where("username = ?", userName).Find(&user).Error; err != nil {
		return err
	}
	return nil
}

func GetTokenInfoByAddress(ChainName string, chainId uint, takenInfo *models.TokenInfo) (*models.TokenInfo, error) {
	tokenClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("token")
	err := tokenClient.FindOne(context.TODO(), bson.M{"chainName": ChainName, "chainId": chainId, "address": takenInfo.Address}).Decode(takenInfo)
	if err != nil {
		return nil, err
	}

	return takenInfo, nil
}

func ReadUserAddress(userID string, pageIndex uint, pageSize uint, addressVal string, chainId string) ([]*models.WatchAddressConfig, int64, error) {
	findOptions := options.Find()
	findOptions.SetSkip(int64(pageIndex))
	findOptions.SetLimit(int64(pageSize))
	findOptions.SetSort(bson.D{{"_id", -1}})
	filter := bson.M{"userId": userID, "type": "udun"}
	if addressVal != "" {
		filter["address"] = addressVal
	}
	if chainId != "" {
		chainIdInt, _ := strconv.Atoi(chainId)
		filter["chainId"] = chainIdInt
	}
	var address []*models.WatchAddressConfig
	userTokenClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	data, err := userTokenClient.Find(context.TODO(), filter, findOptions)
	if err != nil {
		return nil, 0, err
	}
	err = data.All(context.Background(), &address)
	if err != nil {
		return nil, 0, err
	}
	documents, err := userTokenClient.CountDocuments(context.TODO(), filter)
	if err != nil {
		return nil, 0, err
	}

	return address, documents, nil
}

func ReadOrderByID(userId string, pageIndex uint, pageSize uint, orderId string, orderStatus string) ([]*models.Order, int64, error) {
	orderClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("order")
	findOptions := options.Find()
	findOptions.SetSkip(int64(pageIndex))
	findOptions.SetLimit(int64(pageSize))
	findOptions.SetSort(bson.D{{"_id", -1}})

	filter := bson.M{"userId": userId}
	if orderId != "" {
		objId, _ := primitive.ObjectIDFromHex(orderId)
		filter["_id"] = objId
	}
	if orderStatus != "" {
		orderStatusInt, _ := strconv.Atoi(orderStatus)
		filter["orderStatus"] = orderStatusInt
	}
	var order []*models.Order
	data, err := orderClient.Find(context.TODO(), filter, findOptions)
	if err != nil {
		return nil, 0, err
	}
	err = data.All(context.Background(), &order)
	if err != nil {
		return nil, 0, err
	}
	documents, err := orderClient.CountDocuments(context.TODO(), filter)
	if err != nil {
		return nil, 0, err
	}
	return order, documents, err
}

func (u UdunAPI) GetConfigList(c *gin.Context) {
	language := c.MustGet("language").(string)
	var configList []*models.ScanConfig
	configClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("scan_config")
	data, err := configClient.Find(context.TODO(), bson.M{"type": "DAPP"})
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	err = data.All(context.Background(), &configList)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	response := utils.GetResponse(nil, utils.Success, configList, language)
	c.JSON(http.StatusOK, response)

}

// 产品升级
func (u UdunAPI) ProductUpgrade(c *gin.Context) {

	var orderInfo models.Order
	var body models.CallBackBody
	bodyStr := c.PostForm("body")
	language := "zh-cn"
	err := json.Unmarshal([]byte(bodyStr), &body)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	var generateAddressConfig models.GenerateAddressConfig
	addressClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("generate_address_config")
	err = addressClient.FindOne(context.TODO(), bson.M{"address": body.Address}).Decode(&generateAddressConfig)
	if err != nil {
		response := utils.GetResponse(err, utils.UpdateError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	userClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user")
	objId, err := primitive.ObjectIDFromHex(generateAddressConfig.UserId)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	orderClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("order")
	//orderFilter := bson.D{{"userId", generateAddressConfig.UserId}, {"orderStatus", "1"}}
	//orderUpdate := bson.D{
	//	{"$set", bson.D{
	//		{"orderStatus", 2},
	//	}},
	//}
	//_, err = orderClient.UpdateMany(context.TODO(), orderFilter, orderUpdate)

	findOptions := options.FindOne()
	findOptions.SetSort(bson.D{{"_id", -1}})
	err = orderClient.FindOne(context.TODO(), bson.M{"userId": generateAddressConfig.UserId}, findOptions).Decode(&orderInfo)

	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	var productInfo models.Product
	productClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("product")
	objIdPro, _ := primitive.ObjectIDFromHex(orderInfo.ProductId)
	err = productClient.FindOne(context.TODO(), bson.M{"_id": objIdPro}).Decode(&productInfo)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	//在user_token里加入要监听的代币地址 在这里判断是不是该地址body.CoinType
	//这里查找系统用户
	var systemUserInfo models.User
	err = userClient.FindOne(context.TODO(), bson.M{"role": "1"}).Decode(&systemUserInfo)
	if err != nil {
		response := utils.GetResponse(err, utils.UserNotExist, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	var userToken []*models.UserToken
	var flag = true
	userTokenClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_token")
	data, err := userTokenClient.Find(context.TODO(), bson.M{"userId": systemUserInfo.Id})
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbFindDataError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	err = data.All(context.TODO(), &userToken)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	var tokenSymnol string
	for _, token := range userToken {
		if token.Address == body.CoinType {
			flag = false
			tokenSymnol = token.Symbol
			break
		}
	}
	if flag {
		response := utils.GetResponse(errors.New("tokenAddress is mistake"), utils.MongodbFindDataError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	//判断充币数量  先把精度算出来 再用amount除精度得到充币数量 再去和product里fee字段判断
	if body.Amount < productInfo.Fee {
		response := utils.GetResponse(errors.New("amount is mistake"), utils.ServerError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	//计算到期时间
	var userInfo models.User
	err = userClient.FindOne(context.TODO(), bson.M{"_id": objId}).Decode(&userInfo)
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbFindDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	update := bson.M{}
	var category models.Category
	categoryClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("category")
	categoryId, _ := primitive.ObjectIDFromHex(productInfo.CategoryId)
	categoryClient.FindOne(context.TODO(), bson.M{"_id": categoryId}).Decode(&category)

	var maturityTime int64
	if category.Desc == "blockWatch" {
		maturityTime = tools.AddTimestamp(userInfo.MaturityTime, productInfo.Months, productInfo.Type)
		update = bson.M{"$set": bson.M{"maturityTime": maturityTime}}
	}

	if category.Desc == "dapp" {
		maturityTime = tools.AddTimestamp(userInfo.DappMaturityTime, productInfo.Months, productInfo.Type)
		update = bson.M{"$set": bson.M{"dappMaturityTime": maturityTime}}
	}

	if update == nil {
		response := utils.GetResponse(errors.New("product desc error"), utils.ServerError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	//order表
	orderId, _ := primitive.ObjectIDFromHex(orderInfo.Id)
	_, err = orderClient.UpdateOne(context.TODO(), bson.M{"_id": orderId}, bson.M{"$set": bson.M{"maturityTime": maturityTime, "orderStatus": 2, "payOrderTime": time.Now().Unix()}})
	if err != nil {
		response := utils.GetResponse(err, utils.UpdateError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}
	//回调成功 在user表里加时间戳
	filter := bson.M{"_id": objId}

	_, err = userClient.UpdateOne(context.TODO(), filter, update)
	if err != nil {
		response := utils.GetResponse(err, utils.UpdateError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	var emailConfig models.EmailConfig
	emailClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("email_config")
	emailClient.FindOne(context.TODO(), bson.M{}).Decode(&emailConfig)

	//发送邮件
	str := "用户:" + userInfo.Username + "充值了" + generateAddressConfig.ChainName + "链下的" + body.Amount + "个" + tokenSymnol + "代币"
	emailParams := mail.Options{
		MailHost: global.EmailConfig.Host,
		MailPort: global.EmailConfig.Port,
		MailUser: global.EmailConfig.User,
		MailPass: global.EmailConfig.Password,
		MailTo:   emailConfig.ToEmail,
		Subject:  "用户充值提醒",
		Body:     str,
	}
	mail.Send(&emailParams)

	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)

}

func (u UdunAPI) GetUpCoinList(c *gin.Context) {
	language := c.MustGet("language").(string)
	userInfo := c.MustGet("userInfo").(models.User)
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	chainName := c.Query("chainName")
	symbolName := c.Query("symbolName")
	status := c.Query("status") //0:会员到期 1:成功 2:手续费地址没钱
	var addressConfigList []*models.WatchAddressConfig
	addressConfigClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	data, err := addressConfigClient.Find(context.TODO(), bson.M{"userId": userInfo.Id})
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			response := utils.GetResponse(nil, utils.Success, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		response := utils.GetResponse(err, utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	err = data.All(context.Background(), &addressConfigList)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	var addressList []string
	for _, config := range addressConfigList {
		addressList = append(addressList, config.Address)
	}

	if len(addressList) == 0 {
		response := utils.GetResponse(nil, utils.Success, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var upCoinList []models.UpCoin
	upCoinClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("up_coin")

	findOptions := options.Find()
	findOptions.SetSkip(int64(pageIndex))
	findOptions.SetLimit(int64(pageSize))
	findOptions.SetSort(bson.D{{"_id", -1}})
	filter := bson.M{"to": bson.M{"$in": addressList}}
	txHash := c.Query("txHash")
	address := c.Query("address") //from或者to
	startTime := c.Query("startTime")
	endTime := c.Query("endTime")
	if chainName != "" {
		filter["chainName"] = chainName
	}
	if symbolName != "" {
		filter["symbolName"] = symbolName
	}
	if txHash != "" {
		filter["txHash"] = txHash
	}
	if status != "" {
		filter["status"], _ = strconv.Atoi(status)
	}
	if address != "" {
		filter["$or"] = bson.A{
			bson.M{"from": address},
			bson.M{"to": address},
		}
	}

	if startTime != "" {
		startTimeInt, _ := strconv.Atoi(startTime)
		// 确保timestamp字段存在，并初始化为一个map
		if _, ok := filter["timestamp"]; !ok {
			filter["timestamp"] = bson.M{}
		}
		// 现在可以安全地给timestamp下的$gte赋值
		timestampMap, ok := filter["timestamp"].(bson.M)
		if !ok {
			// 如果filter["timestamp"]不是map，则初始化它
			timestampMap = bson.M{}
			filter["timestamp"] = timestampMap
		}
		timestampMap["$gte"] = startTimeInt
	}
	if endTime != "" {
		endTimeInt, _ := strconv.Atoi(endTime)
		// 同上，确保timestamp字段存在，并初始化为一个map
		if _, ok := filter["timestamp"]; !ok {
			filter["timestamp"] = bson.M{}
		}
		// 给timestamp下的$lte赋值
		timestampMap, ok := filter["timestamp"].(bson.M)
		if !ok {
			// 如果filter["timestamp"]不是map，则初始化它
			timestampMap = bson.M{}
			filter["timestamp"] = timestampMap
		}
		timestampMap["$lte"] = endTimeInt
	}

	result, err := upCoinClient.Find(context.TODO(), filter, findOptions)
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			response := utils.GetResponse(nil, utils.Success, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		response := utils.GetResponse(err, utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	err = result.All(context.TODO(), &upCoinList)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var total int64

	total, err = upCoinClient.CountDocuments(context.TODO(), filter)
	if err != nil {
		response := utils.GetResponse(err, utils.GetCountError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	responseData := global.Page{
		Total: total,
		List:  upCoinList,
	}
	response := utils.GetResponse(nil, utils.Success, responseData, language)
	c.JSON(http.StatusOK, response)
}

func (u UdunAPI) WithdrawList(c *gin.Context) {
	language := c.MustGet("language").(string)

	var withdrawList []*models.Withdraw

	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	optionsFind := options.Find()
	optionsFind.SetSkip(int64(pageIndex))
	optionsFind.SetLimit(int64(pageSize))
	optionsFind.SetSort(bson.D{{"_id", -1}})
	userInfo := c.MustGet("userInfo").(models.User)
	filter := bson.M{"userId": userInfo.Id}
	txHash := c.Query("txHash")
	address := c.Query("address")
	startTime := c.Query("startTime")
	endTime := c.Query("endTime")
	chainName := c.Query("chainName")
	tokenSymbol := c.Query("tokenSymbol")
	status := c.Query("status")

	if chainName != "" {
		filter["chainName"] = chainName
	}
	if tokenSymbol != "" {
		filter["tokenSymbol"] = tokenSymbol
	}

	if txHash != "" {
		filter["txHash"] = txHash
	}
	if address != "" {
		filter["to"] = address
	}

	if status != "" {
		// 转为int
		statusInt, _ := strconv.Atoi(status)
		filter["status"] = statusInt
	}

	if startTime != "" {
		startTimeInt, _ := strconv.Atoi(startTime)
		// 确保timestamp字段存在，并初始化为一个map
		if _, ok := filter["timestamp"]; !ok {
			filter["timestamp"] = bson.M{}
		}
		// 现在可以安全地给timestamp下的$gte赋值
		timestampMap, ok := filter["timestamp"].(bson.M)
		if !ok {
			// 如果filter["timestamp"]不是map，则初始化它
			timestampMap = bson.M{}
			filter["timestamp"] = timestampMap
		}
		timestampMap["$gte"] = startTimeInt
	}
	if endTime != "" {
		endTimeInt, _ := strconv.Atoi(endTime)
		// 同上，确保timestamp字段存在，并初始化为一个map
		if _, ok := filter["timestamp"]; !ok {
			filter["timestamp"] = bson.M{}
		}
		// 给timestamp下的$lte赋值
		timestampMap, ok := filter["timestamp"].(bson.M)
		if !ok {
			// 如果filter["timestamp"]不是map，则初始化它
			timestampMap = bson.M{}
			filter["timestamp"] = timestampMap
		}
		timestampMap["$lte"] = endTimeInt
	}

	findOptions := options.Find()
	findOptions.SetSort(bson.D{{"_id", -1}})

	withdrawClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("withdraw")
	find, err := withdrawClient.Find(context.TODO(), filter, findOptions)
	if err != nil {
		response := utils.GetResponse(err, utils.GetWithdrawError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	err = find.All(context.TODO(), &withdrawList)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	total, err := withdrawClient.CountDocuments(context.TODO(), filter)
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbCountError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	responseData := global.Page{
		Total: total,
		List:  withdrawList,
	}
	response := utils.GetResponse(nil, utils.Success, responseData, language)
	c.JSON(http.StatusOK, response)

}

func (u UdunAPI) GetAllTokenList(c *gin.Context) {

	language := c.MustGet("language").(string)
	var tokenList []*models.TokenInfo
	chainName := c.Query("chainName")
	chainId := c.Query("chainId")
	//pageIndex := c.MustGet("pageIndex").(uint)
	//pageSize := c.MustGet("pageSize").(uint)
	tokenClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("token")

	chainIdUint, _ := strconv.ParseUint(chainId, 10, 0)

	//option := options.Find()
	//option.SetSkip(int64(pageIndex))
	//option.SetLimit(int64(pageSize))
	data, err := tokenClient.Find(context.TODO(), bson.M{"chainName": chainName, "chainId": chainIdUint})
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbFindDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	err = data.All(context.TODO(), &tokenList)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	response := utils.GetResponse(nil, utils.Success, tokenList, language)
	c.JSON(http.StatusOK, response)
}

func (u UdunAPI) GetUserTokenList(c *gin.Context) {
	language := c.MustGet("language").(string)
	userInfo := c.MustGet("userInfo").(models.User)
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)

	findOptions := options.Find()
	findOptions.SetSkip(int64(pageIndex))
	findOptions.SetLimit(int64(pageSize))

	var userTokenList []*models.UserToken

	userTokenClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_token")

	find, err := userTokenClient.Find(context.TODO(), bson.M{"userId": userInfo.Id}, findOptions)
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			response := utils.GetResponse(nil, utils.Success, nil, language)
			c.JSON(http.StatusOK, response)

		} else {
			response := utils.GetResponse(err, utils.ServerError, nil, language)
			c.JSON(http.StatusOK, response)
		}
		return
	}

	err = find.All(context.TODO(), &userTokenList)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	total, err := userTokenClient.CountDocuments(context.TODO(), bson.M{"userId": userInfo.Id})
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbCountError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	data := global.Page{
		Total: total,
		List:  userTokenList,
	}
	response := utils.GetResponse(nil, utils.Success, data, language)
	c.JSON(http.StatusOK, response)

}

func (u UdunAPI) GetCallbackList(c *gin.Context) {
	resultData := global.Page{
		Total: 0,
		List:  nil,
	}
	userInfo := c.MustGet("userInfo").(models.User)
	language := c.MustGet("language").(string)
	var addressList []string
	var addressConfig []*models.GenerateAddressConfig
	addressConfigClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	data, err := addressConfigClient.Find(context.TODO(), bson.M{"userId": userInfo.Id, "type": "udun"})
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			response := utils.GetResponse(nil, utils.Success, resultData, language)
			c.JSON(http.StatusOK, response)
			return
		}
		response := utils.GetResponse(err, utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	err = data.All(context.TODO(), &addressConfig)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	for _, config := range addressConfig {
		addressList = append(addressList, config.Address)
	}
	if len(addressConfig) == 0 {
		response := utils.GetResponse(err, utils.Success, resultData, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var callBackList []*models.CollectionCallback
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	findOptions := options.Find()
	findOptions.SetSkip(int64(pageIndex))
	findOptions.SetLimit(int64(pageSize))
	findOptions.SetSort(bson.D{{"_id", -1}})
	callBackClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("collection_callback")
	var filter bson.D
	// 构建查询过滤器，使用$in操作符匹配addressList中的值
	filter = append(filter, bson.E{Key: "$or", Value: bson.A{
		bson.D{{Key: "from", Value: bson.D{{Key: "$in", Value: addressList}}}},
		bson.D{{Key: "toAddress", Value: bson.D{{Key: "$in", Value: addressList}}}},
	}})
	txHash := c.Query("txHash")
	address := c.Query("address")
	if txHash != "" {
		filter = append(filter, bson.E{Key: "txHash", Value: txHash})
	}
	if address != "" {
		filter = append(filter, bson.E{Key: "toAddress", Value: address})
	}
	find, err := callBackClient.Find(context.TODO(), filter, findOptions)
	if err != nil {
		if errors.Is(err, mongo.ErrNoDocuments) {
			response := utils.GetResponse(nil, utils.Success, resultData, language)
			c.JSON(http.StatusOK, response)
			return
		}
		response := utils.GetResponse(err, utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	err = find.All(context.TODO(), &callBackList)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	total, _ := callBackClient.CountDocuments(context.TODO(), filter)
	resultData.List = callBackList
	resultData.Total = total

	response := utils.GetResponse(nil, utils.Success, resultData, language)
	c.JSON(http.StatusOK, response)

}

// 获取订单列表
func (u UdunAPI) GetProductList(c *gin.Context) {

	//var productList []*models.Product
	productClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("product")
	language := c.MustGet("language").(string)
	//filter := bson.D{{"deleteStatus", "0"}}
	//find, err := productClient.Find(context.TODO(), filter)
	//if err != nil {
	//	response := utils.GetResponse(err, utils.MongodbFindDataError, nil, language)
	//	c.JSON(http.StatusOK, response)
	//	return
	//}
	//err = find.All(context.TODO(), &productList)
	//if err != nil {
	//	response := utils.GetResponse(err, utils.ParseDataError, nil, language)
	//	c.JSON(http.StatusOK, response)
	//	return
	//}

	// 聚合查询
	pipeline := mongo.Pipeline{
		{{"$match", bson.D{{"deleteStatus", "0"}}}}, // 匹配 deleteStatus = 0
		{{"$group", bson.D{
			{"_id", bson.D{
				{"categoryId", "$categoryId"},
			}},
			{"products", bson.D{{"$push", "$$ROOT"}}},
		}}},
		{{"$project", bson.D{
			{"categoryId", "$_id.categoryId"},
			{"categoryName", "$_id.categoryName"}, // 提取 categoryName
			{"desc", "$_id.desc"},
			{"products", "$products"},
			{"_id", 0},
		}}},
	}

	// 执行聚合操作
	cursor, err := productClient.Aggregate(context.TODO(), pipeline)
	if err != nil {
		log.Fatalf("Failed to execute aggregation: %v", err)
	}
	defer cursor.Close(context.TODO())

	var results []bson.M
	if err = cursor.All(context.TODO(), &results); err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var category models.Category

	categoryClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("category")
	// 遍历结果列表并添加字段
	for _, result := range results {
		objId, _ := primitive.ObjectIDFromHex(result["categoryId"].(string))
		categoryClient.FindOne(context.TODO(), bson.M{"_id": objId}).Decode(&category)
		// 添加新字段
		result["categoryName"] = category.Name // 替换为您想添加的字段和值
		result["desc"] = category.Desc
	}

	response := utils.GetResponse(nil, utils.Success, results, language)
	c.JSON(http.StatusOK, response)
}

// 上币申请
func (u UdunAPI) AddApplyToken(c *gin.Context) {
	language := c.MustGet("language").(string)
	var applyToken models.ApplyToken
	err := c.ShouldBindJSON(&applyToken)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	if applyToken.ChainName == "TRX" {
		flag := models.IsValidTrxAddress(applyToken.Address)
		if !flag {
			response := utils.GetResponse(err, utils.AddressFormatError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}

	} else {
		flag := models.IsValidEthereumAddress(applyToken.Address)
		if !flag {
			response := utils.GetResponse(err, utils.AddressFormatError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}

	}

	userInfo := c.MustGet("userInfo").(models.User)
	applyToken.UserId = userInfo.Id
	applyToken.Timestamp = time.Now().Unix()
	err = applyToken.Create(applyToken)
	if err != nil {
		response := utils.GetResponse(err, utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)

}

func (u UdunAPI) GetApplyTokenList(c *gin.Context) {
	language := c.MustGet("language").(string)
	userInfo := c.MustGet("userInfo").(models.User)
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	chainName := c.Query("chainName")
	address := c.Query("address")
	var applyToken models.ApplyToken
	err, applyTokenList, total := applyToken.GetApplyTokenList(userInfo.Id, pageIndex, pageSize, chainName, address)
	if err != nil {
		response := utils.GetResponse(err, utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	data := global.Page{
		Total: total,
		List:  applyTokenList,
	}
	response := utils.GetResponse(nil, utils.Success, data, language)
	c.JSON(http.StatusOK, response)

}

// 获取币种信息
func (u UdunAPI) GetTokenInfo(c *gin.Context) {
	language := c.MustGet("language").(string)
	var tokenInfo models.TokenInfo
	tokenId := c.Query("tokenId")
	objId, _ := primitive.ObjectIDFromHex(tokenId)
	tokenClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("token")
	err := tokenClient.FindOne(context.TODO(), bson.D{{Key: "_id", Value: objId}}).Decode(&tokenInfo)
	if err != nil {
		response := utils.GetResponse(err, utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	response := utils.GetResponse(nil, utils.Success, tokenInfo, language)
	c.JSON(http.StatusOK, response)

}

// 回调补发
func (u UdunAPI) CallbackReissue(c *gin.Context) {
	var callback models.CollectionCallback
	language := c.MustGet("language").(string)
	err := c.ShouldBindJSON(&callback)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	objId := callback.Id
	//objId, _ := primitive.ObjectIDFromHex(callback.Id)
	callbackClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("collection_callback")
	err = callbackClient.FindOne(context.TODO(), bson.D{{"_id", objId}}).Decode(&callback)
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbFindDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var requestData models.RequestData
	err = json.Unmarshal([]byte(callback.RequestData), &requestData)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var watchAddressConfig models.WatchAddressConfig
	watchAddressClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	err = watchAddressClient.FindOne(context.TODO(), bson.D{{"chainName", callback.ChainName}, {"chainId", callback.ChainId}, {"address", callback.ToAddress}}).Decode(&watchAddressConfig)
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbFindDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	callbackData, statusCode, err := utils.SendCallBackV2(&requestData.Body, requestData.UserApikey, requestData.Nonce, requestData.Timestamp, watchAddressConfig.CallBackUrl)
	if err != nil {
		response := utils.GetResponse(err, utils.CallBackError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	if statusCode == 200 {
		update := bson.D{{"$set", bson.D{{"verify", 1}, {"callBackResult", callbackData}, {"callBackUrl", watchAddressConfig.CallBackUrl}}}}
		_, err = callbackClient.UpdateOne(context.TODO(), bson.D{{"_id", objId}}, update)
		if err != nil {
			response := utils.GetResponse(err, utils.UpdateError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		response := utils.GetResponse(nil, utils.Success, nil, language)
		c.JSON(http.StatusOK, response)
	} else {
		response := utils.GetResponse(nil, utils.CallbackFailed, nil, language)
		c.JSON(http.StatusOK, response)
	}

}

// 首页信息
func (u UdunAPI) Index(c *gin.Context) {
	var index models.Index
	userInfo := c.MustGet("userInfo").(models.User)
	language := c.MustGet("language").(string)
	addressClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	addressNum, err := addressClient.CountDocuments(context.TODO(), bson.D{{"userId", userInfo.Id}})
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbCountError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	tokenClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_token")
	tokenNum, err := tokenClient.CountDocuments(context.TODO(), bson.D{{"userId", userInfo.Id}})
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbCountError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	orderClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("order")
	orderNum, err := orderClient.CountDocuments(context.TODO(), bson.D{{"userId", userInfo.Id}, {"orderStatus", 1}})
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbCountError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	upCoinClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("up_coin")
	collectNum, err := upCoinClient.CountDocuments(context.TODO(), bson.D{{"userId", userInfo.Id}, {"status", 0}})
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbCountError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	index.AddressCount = int(addressNum)
	index.TokenCount = int(tokenNum)
	index.OrderNum = int(orderNum)
	index.CollectNum = int(collectNum)
	if userInfo.MaturityTime == 0 {
		index.MaturityTime = "0"
	} else {
		index.MaturityTime = time.Unix(userInfo.MaturityTime, 0).Format("2006-01-02 15:04:05")
	}
	var pictureList []models.Picture
	picturesClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("picture")
	find, err := picturesClient.Find(context.TODO(), bson.D{})
	if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	err = find.All(context.TODO(), &pictureList)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	index.PictureList = pictureList
	response := utils.GetResponse(nil, utils.Success, index, language)
	c.JSON(http.StatusOK, response)
}

// 取消订单
func (u UdunAPI) CancelOrder(c *gin.Context) {
	var order models.Order
	language := c.MustGet("language").(string)
	orderClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("order")
	err := c.ShouldBindJSON(&order)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	objId, err := primitive.ObjectIDFromHex(order.Id)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	err = orderClient.FindOne(context.TODO(), bson.D{{"_id", objId}}).Decode(&order)
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbFindDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	order.OrderStatus = 4
	err = order.Update(orderClient, objId, order)
	if err != nil {
		response := utils.GetResponse(err, utils.UpdateError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)

}

// 添加资产管理
//func (u UdunAPI) AddPocketAddress(c *gin.Context) {
//
//	var userPrivateKey models.UserPrivateKey
//	language := c.MustGet("language").(string)
//	err := c.ShouldBindJSON(&userPrivateKey)
//	if err != nil {
//		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
//		c.JSON(http.StatusOK, response)
//		return
//	}
//
//	// 删除前两位的0x
//	if userPrivateKey.FeeAddress[0:2] == "0x" {
//		userPrivateKey.FeeAddress = userPrivateKey.FeeAddress[2:]
//	}
//	if userPrivateKey.WithdrawAddress[0:2] == "0x" {
//		userPrivateKey.WithdrawAddress = userPrivateKey.WithdrawAddress[2:]
//	}
//
//	_, err = models.PrivateToAddress(userPrivateKey.FeeAddress)
//	if err != nil {
//		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
//		c.JSON(http.StatusOK, response)
//		return
//	}
//	_, err = models.PrivateToAddress(userPrivateKey.WithdrawAddress)
//	if err != nil {
//		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
//		c.JSON(http.StatusOK, response)
//		return
//	}
//
//	userInfo := c.MustGet("userInfo").(models.User)
//	userPrivateKeyClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")
//	documents, err := userPrivateKeyClient.CountDocuments(context.TODO(), bson.D{{"userId", userInfo.Id}, {"mainCoinType", userPrivateKey.MainCoinType}})
//	if err != nil {
//		response := utils.GetResponse(err, utils.MongodbCountError, nil, language)
//		c.JSON(http.StatusOK, response)
//		return
//	}
//	if documents != 0 {
//		response := utils.GetResponse(errors.New("data error"), utils.MongodbDataIsExist, nil, language)
//		c.JSON(http.StatusOK, response)
//		return
//	}
//
//	userPrivateKey.UserId = userInfo.Id
//	err = userPrivateKey.Create()
//	if err != nil {
//		response := utils.GetResponse(err, utils.InsertError, nil, language)
//		c.JSON(http.StatusOK, response)
//		return
//	}
//
//	response := utils.GetResponse(nil, utils.Success, nil, language)
//	c.JSON(http.StatusOK, response)
//
//}

// 添加资产管理
func (u UdunAPI) AddPocketAddress(c *gin.Context) {
	var userPrivateKey models.UserPrivateKey
	language := c.MustGet("language").(string)
	err := c.ShouldBindJSON(&userPrivateKey)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	userInfo := c.MustGet("userInfo").(models.User)
	userPrivateKeyClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")
	documents, err := userPrivateKeyClient.CountDocuments(context.TODO(), bson.D{{"userId", userInfo.Id}, {"mainCoinType", userPrivateKey.MainCoinType}})
	if err != nil {
		response := utils.GetResponse(err, utils.MongodbCountError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	if documents != 0 {
		response := utils.GetResponse(errors.New("data error"), utils.MongodbDataIsExist, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	//userPrivateKey.FeeAddress, userPrivateKey.FeePrivateKey, err = tools.EncryptionKey(userPrivateKey.ChainName)
	//if err != nil {
	//	response := utils.GetResponse(err, utils.ParseDataError, nil, language)
	//	c.JSON(http.StatusOK, response)
	//	return
	//}
	//
	//userPrivateKey.WithdrawAddress, userPrivateKey.WithdrawPrivateKey, err = tools.EncryptionKey(userPrivateKey.ChainName)
	//if err != nil {
	//	response := utils.GetResponse(err, utils.ParseDataError, nil, language)
	//	c.JSON(http.StatusOK, response)
	//	return
	//}

	var flag string
	if userPrivateKey.ChainName == "TRX" {
		flag = "TRX"
	} else {
		flag = "EVM"
	}

	url := "http://192.168.0.188:8888/api/generateAddress?flag=" + flag
	body, err := tools.SendGet(url)
	if err != nil {
		response := utils.GetResponse(errors.New("send get error"), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	var data models.AddressData
	err = json.Unmarshal(body, &data)
	if err != nil {
		response := utils.GetResponse(errors.New("json parse error"), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	if data.Code != 200 {
		response := utils.GetResponse(errors.New("code is not 200"+data.Msg), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	body1, err := tools.SendGet(url)
	if err != nil {
		response := utils.GetResponse(errors.New("send get error"), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	var data1 models.AddressData
	err = json.Unmarshal(body1, &data1)
	if err != nil {
		response := utils.GetResponse(errors.New("json parse error"), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	if data1.Code != 200 {
		response := utils.GetResponse(errors.New("code is not 200"), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	userPrivateKey.FeeAddress = data.Data.Address
	userPrivateKey.WithdrawAddress = data1.Data.Address
	userPrivateKey.FeeBusinessId = data.Data.Id
	userPrivateKey.WithdrawBusinessId = data1.Data.Id
	userPrivateKey.UserId = userInfo.Id
	err = userPrivateKey.Create()
	if err != nil {
		response := utils.GetResponse(err, utils.InsertError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)

}

// 资产管理列表
func (u UdunAPI) GetPocketList(c *gin.Context) {
	pageIndex := c.MustGet("pageIndex").(uint)
	pageSize := c.MustGet("pageSize").(uint)
	userInfo := c.MustGet("userInfo").(models.User)
	language := c.MustGet("language").(string)
	var userPrivateKey models.UserPrivateKey
	userPrivateKey.UserId = userInfo.Id
	userPrivateKeyList, total, err := userPrivateKey.GetListByPage(pageIndex, pageSize, c)
	if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
		response := utils.GetResponse(err, utils.MongodbFindDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	data := global.Page{
		Total: total,
		List:  userPrivateKeyList,
	}
	response := utils.GetResponse(nil, utils.Success, data, language)
	c.JSON(http.StatusOK, response)

}

// 修改资产管理
func (u UdunAPI) UpdatePocketAddress(c *gin.Context) {
	var userPrivateKey models.UserPrivateKey
	language := c.MustGet("language").(string)
	err := c.ShouldBindJSON(&userPrivateKey)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	//if userPrivateKey.FeeAddress != "" {
	//	// 删除前两位的0x
	//	if userPrivateKey.FeeAddress[0:2] == "0x" {
	//		userPrivateKey.FeeAddress = userPrivateKey.FeeAddress[2:]
	//	}
	//
	//	_, err = models.PrivateToAddress(userPrivateKey.FeeAddress)
	//	if err != nil {
	//		response := utils.GetResponse(nil, utils.FeeAddressNotPrivateKey, nil, language)
	//		c.JSON(http.StatusOK, response)
	//		return
	//	}
	//}

	//if userPrivateKey.WithdrawAddress != "" {
	//	// 删除前两位的0x
	//	if userPrivateKey.WithdrawAddress[0:2] == "0x" {
	//		userPrivateKey.WithdrawAddress = userPrivateKey.WithdrawAddress[2:]
	//	}
	//	_, err = models.PrivateToAddress(userPrivateKey.WithdrawAddress)
	//	if err != nil {
	//		response := utils.GetResponse(nil, utils.WithdrawAddressNotPrivateKey, nil, language)
	//		c.JSON(http.StatusOK, response)
	//		return
	//	}
	//}

	userPrivateKey.UserId = c.MustGet("userInfo").(models.User).Id
	err = userPrivateKey.Update()
	if err != nil {
		response := utils.GetResponse(err, utils.UpdateError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)
}

func (u UdunAPI) GetPocketInfo(c *gin.Context) {

	feeAddress := c.Query("feeAddress")
	collectionAddress := c.Query("collectionAddress")
	withdrawAddress := c.Query("withdrawAddress")
	chainName := c.Query("chainName")
	mainCoinType := c.Query("mainCoinType")

	userInfo := c.MustGet("userInfo").(models.User)
	language := c.MustGet("language").(string)

	paramInt, _ := strconv.Atoi(mainCoinType)

	config, err := models.GetInfoInfoByName(chainName, int64(paramInt))
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var token []models.UserToken
	tokenClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_token")
	find, err := tokenClient.Find(context.TODO(), bson.M{"userId": userInfo.Id, "chainName": config.ChainName, "chainId": config.ChainId})
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	err = find.All(context.TODO(), &token)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var withdrawFeeList []models.TokenFee
	var collectionFeeList []models.TokenFee
	var feeBalance string

	if config.ChainName == "TRX" {

		feeBalance, err = models.GetTrxAmount(feeAddress, "_")
		if err != nil {
			response := utils.GetResponse(err, utils.GetCountError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		for _, userToken := range token {
			if len(userToken.Address) <= 20 {
				continue
			}
			withdrawBalance, err := models.GetTrxAmount(withdrawAddress, userToken.Address)
			if err != nil {
				response := utils.GetResponse(err, utils.GetCountError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			var withdrawFee models.TokenFee
			withdrawFee.Name = userToken.Symbol
			withdrawFee.Balance = withdrawBalance
			withdrawFeeList = append(withdrawFeeList, withdrawFee)

			collectionBalance, err := models.GetTrxAmount(collectionAddress, userToken.Address)
			if err != nil {
				response := utils.GetResponse(err, utils.GetCountError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			var collectionFee models.TokenFee
			collectionFee.Name = userToken.Symbol
			collectionFee.Balance = collectionBalance
			collectionFeeList = append(collectionFeeList, collectionFee)

		}

	} else {
		// 通过rpc地址获取公链币余额
		client, err := ethclient.Dial(config.RpcUrl)
		if err != nil {
			response := utils.GetResponse(err, utils.ConnectRpcUrlError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		defer client.Close()

		feeBalance, err = utils.GetMainBalance(client, feeAddress, c)
		if err != nil {
			response := utils.GetResponse(err, utils.GetCountError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}

		for _, userToken := range token {
			if len(userToken.Address) <= 35 {
				continue
			}
			withdrawBalance, err := utils.GetTokenBalance(client, c, userToken.Address, withdrawAddress, userToken.Decimals)
			if err != nil {
				response := utils.GetResponse(err, utils.GetError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			var withdrawFee models.TokenFee
			withdrawFee.Name = userToken.Symbol
			withdrawFee.Balance = withdrawBalance
			withdrawFeeList = append(withdrawFeeList, withdrawFee)

			collectionBalance, err := utils.GetTokenBalance(client, c, userToken.Address, collectionAddress, userToken.Decimals)
			if err != nil {
				response := utils.GetResponse(err, utils.GetError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			var collectionFee models.TokenFee
			collectionFee.Name = userToken.Symbol
			collectionFee.Balance = collectionBalance
			collectionFeeList = append(collectionFeeList, collectionFee)
		}

	}

	var result models.AddressFee
	result.FeeAddress = feeAddress
	result.FeeBalance = feeBalance
	result.WithdrawAddress = withdrawAddress
	result.WithdrawBalance = withdrawFeeList
	result.CollectionAddress = collectionAddress
	result.CollectionFee = collectionFeeList

	response := utils.GetResponse(nil, utils.Success, result, language)
	c.JSON(http.StatusOK, response)
}

func (u UdunAPI) DeletePocketAddress(c *gin.Context) {
	var userPrivateKey models.UserPrivateKey
	language := c.MustGet("language").(string)
	err := c.ShouldBindJSON(&userPrivateKey)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	userInfo := c.MustGet("userInfo").(models.User)
	userPrivateKey.UserId = userInfo.Id
	err = userPrivateKey.Delete()
	if err != nil {
		response := utils.GetResponse(err, utils.DeleteError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)

}

// 更新手续费地址或者提现地址
func (u UdunAPI) UpdateAddress(c *gin.Context) {
	var params struct {
		Type string `json:"type"`
		Id   string `json:"id"`
	}

	language := c.MustGet("language").(string)
	err := c.ShouldBindJSON(&params)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var userPrivateKey models.UserPrivateKey
	client := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")

	objId, _ := primitive.ObjectIDFromHex(params.Id)
	err = client.FindOne(context.TODO(), bson.M{"_id": objId}).Decode(&userPrivateKey)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var flag string

	if userPrivateKey.ChainName == "TRX" {
		flag = "TRX"
	} else {
		flag = "EVM"
	}

	url := "http://192.168.0.188:8888/api/generateAddress?flag=" + flag
	body, err := tools.SendGet(url)
	if err != nil {
		response := utils.GetResponse(errors.New("send get error"+err.Error()), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var data models.AddressData
	err = json.Unmarshal(body, &data)
	if err != nil {
		response := utils.GetResponse(errors.New("json parse error"+err.Error()), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	if data.Code != 200 {
		response := utils.GetResponse(errors.New("code is not 200"+data.Msg), utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	//address, privateKey, err := tools.EncryptionKey(userPrivateKey.ChainName)
	//if err != nil {
	//	response := utils.GetResponse(err, utils.ParseDataError, nil, language)
	//	c.JSON(http.StatusOK, response)
	//	return
	//}

	update := bson.M{}
	//1.手续费地址 2.提现地址
	if params.Type == "1" {
		update["feeAddress"] = data.Data.Address
		update["feeBusinessId"] = data.Data.Id
	} else {
		update["withdrawAddress"] = data.Data.Address
		update["withdrawBusinessId"] = data.Data.Id
	}

	_, err = client.UpdateOne(context.TODO(), bson.M{"_id": objId}, bson.M{"$set": update})
	if err != nil {
		response := utils.GetResponse(err, utils.UpdateError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)
}

// 用户升级--主要是产生预支付订单
func (u UdunAPI) CreateOrder(c *gin.Context) {

	language := c.MustGet("language").(string)
	//如果时用户升级产生的地址 需要在order表加预支付订单
	var product models.Product
	err := c.ShouldBindJSON(&product)
	if err != nil {
		response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	userInfo := c.MustGet("userInfo").(models.User)
	//获取产品信息
	objId, _ := primitive.ObjectIDFromHex(product.Id)
	productClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("product")
	err = productClient.FindOne(context.TODO(), bson.M{"_id": objId}).Decode(&product)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	addressClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("generate_address_config")

	var user models.User
	userClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user")
	err = userClient.FindOne(context.TODO(), bson.M{"role": "1"}).Decode(&user)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var privateList []models.UserPrivateKey
	privateClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")
	dataPrivate, _ := privateClient.Find(context.TODO(), bson.D{{"userId", user.Id}})
	_ = dataPrivate.All(context.TODO(), &privateList)
	if len(privateList) == 0 {
		response := utils.GetResponse(nil, utils.GetCountError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	addressData := make(map[string]string)

	for _, key := range privateList {
		var addressConfig models.GenerateAddressConfig
		err = addressClient.FindOne(context.TODO(), bson.M{"userId": userInfo.Id, "chainName": key.ChainName}).Decode(&addressConfig)
		if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
			response := utils.GetResponse(err, utils.GetError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}

		if addressConfig.Address == "" {
			addressVal, err := models.GenerateAddress(userInfo.Id, key.MainCoinType, key.ChainName)
			if err != nil {
				response := utils.GetResponse(err, utils.GenerateAddressError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			addressData[key.ChainName] = addressVal
		} else {
			addressData[addressConfig.ChainName] = addressConfig.Address
		}

	}

	var order models.Order
	order.ProductId = product.Id
	order.UserId = userInfo.Id
	//order.WatchAddress = generateAddress.Address
	order.OrderStatus = 1
	order.ProductName = product.ProductName
	order.Amount = product.Fee
	order.OrderDuration = product.Months
	order.PayOrderTime = time.Now().Unix()
	order.MaturityTime = time.Now().Unix()
	orderClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("order")
	insertData, err := orderClient.InsertOne(context.TODO(), order)
	if err != nil {
		response := utils.GetResponse(err, utils.InsertError, nil, language)
		c.JSON(http.StatusBadRequest, response)
		return
	}

	data := map[string]interface{}{
		"address": addressData,
		"amount":  product.Fee,
		"orderId": insertData.InsertedID.(primitive.ObjectID).Hex(),
		"time":    strconv.Itoa(product.Months),
		"type":    product.Type,
	}

	response := utils.GetResponse(nil, utils.Success, data, language)
	c.JSON(http.StatusOK, response)

}

// 获取用户到期时间
func (u UdunAPI) GetMaturityTime(c *gin.Context) {
	userInfo := c.MustGet("userInfo").(models.User)
	language := c.MustGet("language").(string)
	loc, _ := time.LoadLocation("Asia/Shanghai")
	data := make(map[string]string)
	if userInfo.MaturityTime == 0 {
		data["blockWatchTime"] = "0"
	} else {
		data["blockWatchTime"] = time.Unix(userInfo.MaturityTime, 0).In(loc).Format("2006-01-02 15:04:05")
	}

	if userInfo.DappMaturityTime == 0 {
		data["dappTime"] = "0"
	} else {
		data["dappTime"] = time.Unix(userInfo.DappMaturityTime, 0).In(loc).Format("2006-01-02 15:04:05")
	}
	response := utils.GetResponse(nil, utils.Success, data, language)
	c.JSON(http.StatusOK, response)
}

// 用户用户待支付订单
func (u UdunAPI) GetPayOrder(c *gin.Context) {
	var order models.Order
	userInfo := c.MustGet("userInfo").(models.User)
	language := c.MustGet("language").(string)
	orderClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("order")
	err := orderClient.FindOne(context.TODO(), bson.D{{"userId", userInfo.Id}, {"orderStatus", bson.D{{"$in", []int{1, 5}}}}}).Decode(&order)
	if errors.Is(err, mongo.ErrNoDocuments) {
		response := utils.GetResponse(nil, utils.Success, nil, language)
		c.JSON(http.StatusOK, response)
		return
	} else {
		//var generateAddress []models.GenerateAddressConfig
		addressClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("generate_address_config")
		//addressList, _ := addressClient.Find(context.TODO(), bson.M{"userId": userInfo.Id})
		//err = addressList.All(context.TODO(), &generateAddress)
		if err != nil {
			response := utils.GetResponse(err, utils.MongodbFindDataError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}

		var user models.User
		userClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user")
		err = userClient.FindOne(context.TODO(), bson.M{"role": "1"}).Decode(&user)
		if err != nil {
			response := utils.GetResponse(err, utils.UserNotExist, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}

		var privateList []models.UserPrivateKey
		privateClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")
		dataPrivate, _ := privateClient.Find(context.TODO(), bson.D{{"userId", user.Id}})
		_ = dataPrivate.All(context.TODO(), &privateList)
		if len(privateList) == 0 {
			response := utils.GetResponse(nil, utils.GetCountError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}

		addressData := make(map[string]string)

		for _, key := range privateList {
			var addressConfig models.GenerateAddressConfig
			err = addressClient.FindOne(context.TODO(), bson.M{"userId": userInfo.Id, "chainName": key.ChainName}).Decode(&addressConfig)
			if err != nil && !errors.Is(err, mongo.ErrNoDocuments) {
				response := utils.GetResponse(err, utils.GetError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			if addressConfig.Address == "" {
				addressVal, err := models.GenerateAddress(userInfo.Id, key.MainCoinType, key.ChainName)
				if err != nil {
					response := utils.GetResponse(err, utils.GenerateAddressError, nil, language)
					c.JSON(http.StatusOK, response)
					return
				}
				addressData[key.ChainName] = addressVal
			} else {
				addressData[addressConfig.ChainName] = addressConfig.Address
			}

		}

		var product models.Product
		objId, _ := primitive.ObjectIDFromHex(order.ProductId)
		productClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("product")
		err = productClient.FindOne(context.TODO(), bson.M{"_id": objId}).Decode(&product)

		data := make(map[string]interface{})
		data["address"] = addressData
		data["id"] = order.Id
		data["amount"] = product.Fee
		data["time"] = strconv.Itoa(order.OrderDuration)
		response := utils.GetResponse(nil, utils.Success, data, language)
		c.JSON(http.StatusOK, response)
		return
	}
}

func (u UdunAPI) ConfirmPayOrder(c *gin.Context) {
	var orderInfo models.Order
	language := c.MustGet("language").(string)
	err := c.ShouldBindJSON(&orderInfo)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	objId, _ := primitive.ObjectIDFromHex(orderInfo.Id)
	orderClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("order")
	filter := bson.D{{"_id", objId}, {"orderStatus", bson.D{{"$ne", 2}}}}
	update := bson.M{"$set": bson.M{"orderStatus": 5}}

	_, err = orderClient.UpdateOne(context.TODO(), filter, update)

	if err != nil {
		response := utils.GetResponse(err, utils.UpdateError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)

}

// getUpCoinAddress  获取所有TRX的地址集合
func getUpCoinAddress(chainID uint) ([]string, error) {
	var tokenAddressListStruct []*models.WatchAddressConfig
	addressClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	find, err := addressClient.Find(context.Background(), bson.D{{"chainId", chainID}})
	if err != nil {
		log.Printf("TRX充币监控，获取address列表失败 %s", err.Error())
		return nil, err
	}
	err = find.All(context.Background(), &tokenAddressListStruct)
	if err != nil {
		log.Printf("TRX充币监控，解析数据失败 %s", err.Error())
		return nil, err
	}

	var addressList []string
	for _, token := range tokenAddressListStruct {
		addressList = append(addressList, token.Address)
	}
	return addressList, nil
}

func doTrxWithdraw(txId string, amount int, body *models.CallBackBody, apikey string, callback string, withdrawId primitive.ObjectID) {
	withdrawClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("withdraw")
	_, err := withdrawClient.UpdateOne(context.TODO(), bson.M{"_id": withdrawId}, bson.M{"$set": bson.M{"status": 3, "txHash": txId}})
	if err != nil {
		log.Printf("存提币哈希失败: %s", err)
		return
	}
	//发送回调
	body.Fee = amount
	body.TxId = txId

	rand.Seed(uint64(time.Now().UnixNano())) // 初始化随机数种子
	randomInt := rand.Intn(10000000)         // 生成一个0到99的随机整数
	//发送post
	go utils.SendCallBack(body, apikey, strconv.Itoa(randomInt), strconv.FormatInt(time.Now().Unix(), 10), callback)

}

// 手动归集
func (u UdunAPI) ManualCollection(c *gin.Context) {
	log.Println("时间戳：", time.Now().Unix())
	language := c.MustGet("language").(string)
	var upCoin models.UpCoin
	err := c.ShouldBindJSON(&upCoin)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	//获取提币信息
	upCoinClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("up_coin")
	err = upCoinClient.FindOne(context.TODO(), bson.D{{"txHash", upCoin.TxHash}}).Decode(&upCoin)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	if upCoin.Status == 1 {
		response := utils.GetResponse(nil, utils.DuplicateCollection, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	//获取链信息
	var config models.ScanConfig
	configClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("scan_config")
	err = configClient.FindOne(context.TODO(), bson.D{{"chainName", upCoin.ChainName}, {"chainId", upCoin.ChainId}}).Decode(&config)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	userInfo := c.MustGet("userInfo").(models.User)

	//获取用户添加的归集地址
	var userPrivateKey models.UserPrivateKey
	privateKeyClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")
	err = privateKeyClient.FindOne(context.Background(), bson.D{{"userId", userInfo.Id}, {"chainName", upCoin.ChainName}}).Decode(&userPrivateKey)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	//查询地址信息
	var address models.WatchAddressConfig
	addressClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	err = addressClient.FindOne(context.TODO(), bson.D{{"address", upCoin.To}}).Decode(&address)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	//获取代币信息
	var tokenInfo models.TokenInfo
	tokenClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("token")
	err = tokenClient.FindOne(context.TODO(), bson.D{{"address", upCoin.TokenAddress}}).Decode(&tokenInfo)
	if err != nil {
		response := utils.GetResponse(err, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	//开始归集
	//1.构建body
	var body models.CallBackBody
	body.Address = upCoin.To
	body.Amount = upCoin.Value
	body.Fee = 0
	//查询币种精度
	body.Decimals = int(tokenInfo.Decimals)
	body.CoinType = tokenInfo.Address
	body.MainCoinType = strconv.Itoa(int(config.UdunId))
	body.BusinessId = ""
	body.BlockHigh = strconv.Itoa(int(upCoin.BlockNumber))
	body.Status = 3
	body.TradeId = upCoin.ID.String()
	body.TradeType = 1
	body.TxId = upCoin.TxHash
	body.Memo = ""

	randomInt := rand.Intn(10000000)
	randomString := strconv.Itoa(randomInt)
	timestamp := strconv.Itoa(int(upCoin.Timestamp))
	sign, err := utils.GetSign(&body, userInfo.ApiKey, randomString, timestamp)
	var RequestData models.RequestData
	RequestData.Body = body
	RequestData.Nonce = randomString
	RequestData.Timestamp = timestamp
	RequestData.Sign = sign
	RequestData.UserApikey = userInfo.ApiKey
	RequestDataStr, err := json.Marshal(RequestData)

	var callBackId primitive.ObjectID
	//1.添加回调数据 0会员到期 发送回掉
	if upCoin.Status == 0 {
		var callBackData models.CollectionCallback
		callBackData.ToAddress = upCoin.To
		callBackData.ChainName = config.ChainName
		callBackData.ChainId = uint(config.ChainID)
		callBackData.BlockNumber = uint64(upCoin.BlockNumber)
		callBackData.TxHash = upCoin.TxHash
		callBackData.From = upCoin.From
		callBackData.To = upCoin.To
		callBackData.Token = upCoin.TokenAddress
		callBackData.Amount = upCoin.Value
		callBackData.CallBackUrl = address.CallBackUrl
		callBackData.Verify = 0
		callBackData.CallBackTime = time.Now().Unix()
		callBackData.RequestData = string(RequestDataStr)
		callBackData.SymbolName = tokenInfo.Name
		callBackData.UserId = userInfo.Id
		insertedId, err := global.DBEngine.Database(global.DbConfig.DbName).Collection("collection_callback").InsertOne(context.Background(), callBackData)
		if err != nil {
			response := utils.GetResponse(err, utils.InsertError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		callBackId = insertedId.InsertedID.(primitive.ObjectID)
	}

	if upCoin.ChainName == "TRX" {
		//node := enums.CreateNode(config.RpcUrl)

		//trxClient := &tronWallet.Crawler{
		//	Node: node,
		//	//Addresses: addressList,
		//}
		//a, err := tronWallet.CreateTronWallet(trxClient.Node, address.PrivateKey)
		//if err != nil {
		//	log.Printf("TRX充币监控，创建转账钱包失败 %s", err.Error())
		//	return
		//}

		amountBig := new(big.Float)
		amountBig.SetString(upCoin.Value)
		amountBig.Mul(amountBig, big.NewFloat(math.Pow10(int(tokenInfo.Decimals))))
		amountBigInt, _ := amountBig.Int(nil)

		//判断是不是转主币
		if tokenInfo.Symbol == "TRX" {
			//主币转账
			//估算gas费
			//feeInSun, err := a.EstimateTransferFee(userPrivateKey.CollectAddress, amountBigInt.Int64())
			//if err != nil {
			//	log.Printf("TRX充币监控，预估手续费失败 %s", err.Error())
			//	return
			//}

			//转手续费
			txId, err := contract.GetTrxTransactionSign(address.Address, "20000000", "", userPrivateKey.FeeBusinessId, config.RpcUrl)
			//txId, err := f.Transfer(address.Address, feeInSun)
			if err != nil {
				response := utils.GetResponse(err, utils.ServerError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			log.Printf("fee地址分配手续费成功: %s", txId)
			//等待手续费到账
			time.Sleep(20 * time.Second)
			//进行归集操作
			//txId2, err := a.Transfer(userPrivateKey.CollectAddress, amountBigInt.Int64())

			txId2, err := contract.GetTrxTransactionSign(userPrivateKey.CollectAddress, amountBigInt.String(), "", address.BusinessId, config.RpcUrl)
			if err != nil {
				log.Printf("TRX充币监控，归集失败 %s", err.Error())
				response := utils.GetResponse(err, utils.ServerError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			log.Printf("归集发送成功成功: %s", txId2)
		} else {

			//转手续费
			txId, err := contract.GetTrxTransactionSign(address.Address, "30000000", "", userPrivateKey.FeeBusinessId, config.RpcUrl)

			//txId, err := f.Transfer(address.Address, feeInSun)
			if err != nil {
				response := utils.GetResponse(err, utils.ServerError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			log.Printf("fee地址分配手续费成功: %s", txId)
			//等待手续费到账
			time.Sleep(20 * time.Second)
			//进行归集操作
			//token := &tronWallet.Token{
			//	ContractAddress: enums.CreateContractAddress(tokenInfo.Address),
			//}

			//txId2, err := a.TransferTRC20(token, userPrivateKey.CollectAddress, amountBigInt.Int64())
			txId2, err := contract.GetTrxTransactionSign(userPrivateKey.CollectAddress, amountBigInt.String(), tokenInfo.Address, address.BusinessId, config.RpcUrl)
			if err != nil {
				log.Printf("TRX充币监控，归集失败 %s", err.Error())
				response := utils.GetResponse(err, utils.ServerError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			log.Printf("归集发送成功成功: %s", txId2)
		}
	} else {

		////手续费
		client, err := ethclient.Dial(config.RpcUrl)
		if err != nil {
			response := utils.GetResponse(err, utils.ConnectRpcUrlError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		defer client.Close()
		ctx, _ := context.WithTimeout(context.Background(), time.Hour)
		gasPrice, err := client.SuggestGasPrice(ctx)
		if err != nil {
			response := utils.GetResponse(err, utils.GasFeeError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		log.Printf("获取gasPrice %s", gasPrice.String())

		// 解析合约ABI
		parsedABI, err := abi.JSON(strings.NewReader(evmAbi.ERC20_ABI))
		if err != nil {
			response := utils.GetResponse(err, utils.AbiParseError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}

		//计算转多少钱
		amountBig := new(big.Float)
		amountBig.SetString(upCoin.Value)
		amountBig.Mul(amountBig, big.NewFloat(math.Pow10(int(tokenInfo.Decimals))))
		amountBigInt, _ := amountBig.Int(nil)

		// 打包要调用的合约方法和参数
		input, err := parsedABI.Pack("transfer", common.HexToAddress(userPrivateKey.CollectAddress), amountBigInt)
		if err != nil {
			response := utils.GetResponse(err, utils.AbiParseError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}

		var gasLimit uint64
		var addressVal common.Address
		toAddressGj := common.HexToAddress(userPrivateKey.CollectAddress)
		// 估算调用方法所需的gas限制
		if len(tokenInfo.Address) >= 35 {
			addressVal = common.HexToAddress(upCoin.TokenAddress)
			gasLimit, _ = client.EstimateGas(ctx, ethereum.CallMsg{
				From: common.HexToAddress(upCoin.To), // 设置调用者地址
				To:   &addressVal,
				Data: input,
			})
		} else {
			// 估算调用方法所需的gas限制
			gasLimit, _ = client.EstimateGas(ctx, ethereum.CallMsg{
				From: common.HexToAddress(upCoin.To), // 设置调用者地址
				To:   &toAddressGj,
			})
		}
		log.Printf("构建交易完成: %d", gasLimit)
		//计算手续费
		gasValue := gasPrice.Mul(gasPrice, big.NewInt(int64(gasLimit)))
		log.Printf("手续费: %s", gasValue.String())

		var tokenAddress string
		if len(tokenInfo.Address) > 10 {
			tokenAddress = tokenInfo.Address
		}
		tx, err := contract.GetTransactionSign(client, userPrivateKey.FeeBusinessId, upCoin.To, config.RpcUrl, gasValue.String(), tokenAddress)
		if err != nil {
			response := utils.GetResponse(err, utils.SendTransactionError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
		log.Printf("fee地址分配手续费成功: %s", tx.Hash())

		for {
			log.Printf("等待确认 %s \n", tx.Hash().Hex())
			receipt, err := client.TransactionReceipt(context.Background(), tx.Hash())
			if err == nil {
				log.Printf("已确认: %s", receipt.TxHash.Hex())
				break
			}
			time.Sleep(time.Second * 3)
		}

		log.Printf("开始归集")
		//进行归集操作
		//privateKeyUpCoin, err := crypto.HexToECDSA(address.PrivateKey)
		//if err != nil {
		//	response := utils.GetResponse(err, utils.ParseDataError, nil, language)
		//	c.JSON(http.StatusOK, response)
		//	return
		//}

		var txgj *types.Transaction
		// 代币
		if len(tokenInfo.Address) >= 35 {
			//txgj, err = contract.SandToken(client, privateKeyUpCoin, addressVal, common.HexToAddress(userPrivateKey.CollectAddress), amountBigInt)

			txgj, err = contract.GetTransactionSign(client, address.BusinessId, toAddressGj.Hex(), config.RpcUrl, amountBigInt.String(), tokenAddress)
			if err != nil {
				response := utils.GetResponse(err, utils.SendTransactionError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
		} else {
			// 主币 Main(client, privateKeyUpCoin, amountBigInt, toAddressGj)
			//txgj, err = contract.SendTransactionMain(client, address.BusinessId, amountBigInt, toAddressGj)
			txgj, err = contract.GetTransactionSign(client, address.BusinessId, toAddressGj.Hex(), config.RpcUrl, amountBigInt.String(), "")
			if err != nil {
				response := utils.GetResponse(err, utils.SendTransactionError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
		}

		log.Printf("归集发送成功成功: %s", txgj.Hash())
	}
	_, err = upCoinClient.UpdateOne(context.Background(), bson.M{"_id": upCoin.ID}, bson.M{"$set": bson.M{"status": 1}})
	if err != nil {
		log.Printf("EVM主币充币监控，更新%s状态失败  %s", upCoin.ID.String(), err.Error())
		response := utils.GetResponse(err, utils.ServerError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	//发送post
	if upCoin.Status == 0 {
		go func() {
			body.Status = 3
			err := utils.SendCallBackV3(&body, sign, randomString, timestamp, address.CallBackUrl, callBackId)
			if err != nil {
				log.Printf("充币监控，发送回调失败 %s", err)
				response := utils.GetResponse(err, utils.ServerError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
		}()
	}

	response := utils.GetResponse(nil, utils.Success, nil, language)
	c.JSON(http.StatusOK, response)
	return
}

func (u UdunAPI) BatchUpdatePocket(c *gin.Context) {
	var privateKeyList []models.UserPrivateKey
	privateKeyClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")
	list, err := privateKeyClient.Find(context.TODO(), bson.M{})
	if err != nil {
		log.Printf("获取列表失败: %s", err)
		return
	}
	err = list.All(context.TODO(), &privateKeyList)
	if err != nil {
		log.Printf("列表解析失败: %s", err)
		return
	}

	for _, privateKey := range privateKeyList {
		if privateKey.FeePrivateKey == "" {
			privateKey.FeeAddress, privateKey.FeePrivateKey, err = tools.EncryptionKey(privateKey.ChainName)
			if err != nil {
				fmt.Printf("生成地址手续费地址报错报错 %s", err)
				continue
			}

		}
		if privateKey.WithdrawPrivateKey == "" {
			privateKey.WithdrawAddress, privateKey.WithdrawPrivateKey, err = tools.EncryptionKey(privateKey.ChainName)
			if err != nil {
				fmt.Printf("生成地址手续费地址报错报错 %s", err)
				continue
			}
		}

		ogbId, _ := primitive.ObjectIDFromHex(privateKey.Id)
		filter := bson.M{"_id": ogbId}
		update := bson.D{
			{"$set", bson.D{
				{"feeAddress", privateKey.FeeAddress},
				{"withdrawAddress", privateKey.WithdrawAddress},
				{"feePrivateKey", privateKey.FeePrivateKey},
				{"withdrawPrivateKey", privateKey.WithdrawPrivateKey},
			}},
		}
		_, err = privateKeyClient.UpdateOne(context.TODO(), filter, update)
		if err != nil {
			fmt.Printf("更新失败 %s", err)
			continue
		}

	}

}

func (u UdunAPI) BatchUpdateAddress(c *gin.Context) {

	//generateClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("generate_address_config")
	//var addressList []models.GenerateAddressConfig
	//generateList, err := generateClient.Find(context.Background(), bson.M{})
	//if err != nil {
	//
	//}

	watchClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("watch_address_config")
	var addressList []models.WatchAddressConfig
	watchList, err := watchClient.Find(context.Background(), bson.M{})
	if err != nil {

	}

	err = watchList.All(context.Background(), &addressList)
	if err != nil {

	}

	for _, address := range addressList {

		var flag string
		if address.ChainName == "TRX" {
			flag = "TRX"
		} else {
			flag = "EVM"
		}

		url := "http://192.168.0.188:8888/api/generateAddress?flag=" + flag
		body, err := tools.SendGet(url)
		if err != nil {
			log.Printf("调用接口失败: %s,id: %s", err, address.Id)
			continue
		}

		var data models.AddressData
		err = json.Unmarshal(body, &data)
		if err != nil {
			log.Printf("解析返回值失败: %s,id: %s", err, address.Id)
			continue
		}
		if data.Code != 200 {
			log.Printf("返回值不是200: %s,id: %s", err, address.Id)
			continue
		}

		_, err = watchClient.UpdateOne(context.TODO(), bson.M{"_id": address.Id}, bson.M{"$set": bson.M{"address": data.Data.Address, "businessId": data.Data.Id}})
		if err != nil {
			log.Printf("更新失败: %s,id: %s,address: %s,busineddId: %s", err, address.Id, data.Data.Address, data.Data.Id)
			continue
		}

	}

	response := utils.GetResponse(nil, utils.Success, nil, "zh")
	c.JSON(http.StatusOK, response)
	return

}

type WithdrawData struct {
	Id           string `json:"id"`
	TokenAddress string `json:"tokenAddress"` //主币传_ 有就是代币
	Type         int    `json:"type"`         //1.手续费地址 2.提现地址
	Address      string `json:"address"`
}

// 把手续费地址和提现地址的钱提现到归集地址
func (u UdunAPI) WithdrawToCollection(c *gin.Context) {
	language := c.MustGet("language").(string)
	var params WithdrawData
	err := c.ShouldBindJSON(&params)
	if err != nil {
		response := utils.GetResponse(err, utils.ParamBindError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	privateClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("user_private_key")
	var userPrivateKey models.UserPrivateKey
	objId, _ := primitive.ObjectIDFromHex(params.Id)
	err = privateClient.FindOne(context.TODO(), bson.M{"_id": objId}).Decode(&userPrivateKey)

	if userPrivateKey.Id == "" {
		response := utils.GetResponse(nil, utils.GetError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var tokenInfo models.TokenInfo
	if params.TokenAddress != "" {

		err = global.DBEngine.Database(global.DbConfig.DbName).Collection("token").FindOne(context.TODO(), bson.M{"address": params.TokenAddress}).Decode(&tokenInfo)
		if err != nil {
			response := utils.GetResponse(errors.New("token is exist"), utils.GetError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}
	}

	var scanConfig models.ScanConfig
	configClient := global.DBEngine.Database(global.DbConfig.DbName).Collection("scan_config")
	err = configClient.FindOne(context.TODO(), bson.M{"udunId": userPrivateKey.MainCoinType, "chainName": userPrivateKey.ChainName}).Decode(&scanConfig)
	if err != nil {
		response := global.Response{
			Code: http.StatusBadRequest,
			Data: nil,
			Msg:  "select data failed:" + err.Error(),
		}
		c.JSON(http.StatusOK, response)
		return
	}

	// 通过rpc地址获取公链币余额
	client, err := ethclient.Dial(scanConfig.RpcUrl)
	if err != nil {
		response := utils.GetResponse(err, utils.ConnectRpcUrlError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}
	defer client.Close()

	feeBalance := "0"

	if userPrivateKey.ChainName == "TRX" {

		var tokenAddress string
		if params.TokenAddress == "" {
			tokenAddress = "_"
		} else {
			tokenAddress = params.TokenAddress
		}
		feeBalance, err = models.GetTrxAmount(params.Address, tokenAddress)
		if err != nil {
			response := utils.GetResponse(err, utils.GetCountError, nil, language)
			c.JSON(http.StatusOK, response)
			return
		}

	} else {

		if params.TokenAddress == "" {

			ctx, _ := context.WithTimeout(context.Background(), time.Minute)
			gasPrice, err := client.SuggestGasPrice(ctx)
			if err != nil {
				response := utils.GetResponse(err, utils.GetCountError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}

			toAddressGj := common.HexToAddress(userPrivateKey.CollectAddress)
			// 估算调用方法所需的gas限制
			gasLimit, err := client.EstimateGas(ctx, ethereum.CallMsg{
				From: common.HexToAddress(params.Address), // 设置调用者地址
				To:   &toAddressGj,
			})

			//计算手续费
			gasValue := gasPrice.Mul(gasPrice, big.NewInt(int64(gasLimit)))

			feeBalanceBig, err := client.BalanceAt(c, common.HexToAddress(params.Address), nil)
			if err != nil {
				response := utils.GetResponse(err, utils.GetCountError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
			feeBalance = new(big.Int).Sub(feeBalanceBig, gasValue).String()
		} else {
			feeBalance, err = utils.GetTokenBalance(client, c, tokenInfo.Address, params.Address, 0)
			if err != nil {
				response := utils.GetResponse(err, utils.GetCountError, nil, language)
				c.JSON(http.StatusOK, response)
				return
			}
		}
	}

	if feeBalance == "0" {
		response := utils.GetResponse(errors.New("当前账户余额为0"), utils.GetCountError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	var businessId string
	if params.Type == 1 {
		businessId = userPrivateKey.FeeBusinessId
	} else {
		businessId = userPrivateKey.WithdrawBusinessId
	}

	_, err = contract.GetTransactionSign(client, businessId, userPrivateKey.CollectAddress, scanConfig.RpcUrl, feeBalance, params.TokenAddress)
	if err != nil {
		response := utils.GetResponse(err, utils.SendTransactionError, nil, language)
		c.JSON(http.StatusOK, response)
		return
	}

	response := utils.GetResponse(nil, utils.Success, nil, "zh")
	c.JSON(http.StatusOK, response)
	return

}
